package compiler.syntax.nonTerminal;

import java.util.ArrayList;
import java.util.List;

import compiler.CompilerContext;
import compiler.intermediate.Temporal;
import compiler.semantic.symbol.SymbolConstant;
import compiler.semantic.symbol.SymbolFunction;
import compiler.semantic.symbol.SymbolParameter;
import compiler.semantic.symbol.SymbolVariable;
import compiler.semantic.type.TypeArray;
import compiler.semantic.type.TypeFunction;
import compiler.semantic.type.TypeSimple;

import es.uned.lsi.compiler.intermediate.IntermediateCodeBuilder;
import es.uned.lsi.compiler.intermediate.OperandIF;
import es.uned.lsi.compiler.intermediate.QuadrupleIF;
import es.uned.lsi.compiler.intermediate.TemporalFactory;
import es.uned.lsi.compiler.semantic.ScopeIF;
import es.uned.lsi.compiler.semantic.type.TypeIF;

public class Expresion extends NonTerminal {

	private TypeIF type;		//Tipo de esta subexpresion.

	private enum TExp {CTE_BOOL, CTE_INT, VAR, PARAM, CAMPO, ELEM_ARRAY, OP, FUNC };
	
	private TExp texp;
	private boolean bcte;
	private int icte;
	private Expresion e1;
	private Expresion e2;
	private List<Expresion> listaExp = null;
	//private Campo campo;
	private SymbolConstant cons;
	private SymbolVariable var;
	private SymbolParameter param;
	private Operador op;
	private SymbolFunction func;

	private OperandIF resultOperand;
	private List<QuadrupleIF> quadrupleList;
	
	public Expresion(Expresion e1, Expresion e2, Operador op) {
		this.e1 = e1;
		this.e2 = e2;
		this.op = op;
		texp = TExp.OP;

		switch (op.getOperador()){
			case Operador.OP_MAS:
			case Operador.OP_MENOS:
				type = TypeSimple.TS_ENT;
				break;
			case Operador.OP_MAYOR:
			case Operador.OP_MENOR:
			case Operador.OP_AND:
			case Operador.OP_IGUAL:
			case Operador.OP_DIST:
				type = TypeSimple.TS_BOOL;
				break; 	
		}
	}
	
	public Expresion (boolean b) {
		type = TypeSimple.TS_BOOL;
		texp = TExp.CTE_BOOL;
		bcte = b;
	}
	
	public Expresion (int n) {
		type = TypeSimple.TS_ENT;
		texp = TExp.CTE_INT;
		icte = n;
	}
	
	public Expresion (SymbolVariable var) {
		this.var = var;
		type = var.getType();
		texp = TExp.VAR;
	}
	
	public Expresion (SymbolParameter param) {
		this.param = param;
		type = param.getType();
		texp = TExp.PARAM;
	}
	
	public Expresion (Expresion e1, Expresion e2) {
		listaExp = new ArrayList<Expresion>(2);
		listaExp.add(e1);
		listaExp.add(e2);
		type = ((TypeArray)e1.type).typeBase();
		texp = TExp.ELEM_ARRAY;
	}
	
//	public Expresion (Expresion e1, Campo campo){
//		listaExp = new ArrayList<Expresion>(1);
//		listaExp.add(e1);
//		this.campo = campo;
//		type = campo.getTipo();
//		texp = TExp.CAMPO;
//	}
	
	public Expresion (SymbolFunction func, List<Expresion> parametros){
		listaExp = new ArrayList<Expresion>(parametros.size());
		listaExp.addAll(parametros);
		this.func = func;
		type = ((TypeFunction)func.getType()).getTretorno();
		texp = TExp.FUNC;
	}

	
	public TypeIF getType() {
		return type;
	}

	public void setType(TypeIF type) {
		this.type = type;
	}

	public OperandIF getResultOperand() {
		return resultOperand;
	}

	public void setResultOperand(OperandIF operand) {
		this.resultOperand = operand;
	}

	public List<QuadrupleIF> getCode() {
		return quadrupleList;
	}

	public void setCode(List<QuadrupleIF> quadruple) {
		this.quadrupleList = quadruple;
	}

	@Override
	public String toString() {
		return "Expresion [type=" + type.getName() + ", texp=" + texp + ", bcte=" + bcte
				+ ", icte=" + icte + ", listaExp=" + listaExp + ", var=" + var + ", param=" + param + ", op=" + op
				+ ", func=" + func + "]";
	}

	public void generarCodigoIntermedioExpresion(){
		
		if (e1 != null && e2 != null && op != null){
			ScopeIF scope = CompilerContext.getScopeManager().getCurrentScope();
			TemporalFactory tf = new TemporalFactory(scope);
			IntermediateCodeBuilder cb = new IntermediateCodeBuilder(scope);
			Temporal t = (Temporal)tf.create();	
			cb.addQuadruples (e1.getIntermediateCode ()); 
			cb.addQuadruples (e2.getIntermediateCode ()); 
			OperandIF o1 = e1.getResultOperand();
			OperandIF o2 = e2.getResultOperand();
			cb.addQuadruple (op.toString(),t,o1,o2);			
			cb.create();	
		}
		
		
	}
}
